<template>
    <!-- 领标编辑 -->
    <UxDialog :visible="uploader && uploader.status != 'select'" @close="cancel()">
        <div class="uploader" v-if="uploader" :error="error ? 'error' : ''">
            <h2>Upload file</h2>
            <h3 v-text="uploader.file ? uploader.file.name : 'uploading'"></h3>
            <figure>
                <img v-if="uploader.image" :src="uploader.image.src" :style="$fiexImage(uploader.image.width,uploader.image.height,1)">
                <img v-else-if="error" class="uploader-error" src="@/assets/images/error.png">
                <UxLoading v-else />
            </figure>
            <span>
                <em v-text="error" v-if="error"></em>
                <em v-text="uploader.percent + '%'" v-else></em>
            </span>
            <strong>
                <b :style="{width: uploader.percent + '%'}"></b>
            </strong>
            <button @click="cancel()">Cancel</button>
        </div>
    </UxDialog>

</template>
<script>
export default {
    name: "UserUploader",
    props: {
        folder: { type: String, require: false, default: 'upload' },
    },
    data () {
        return {
            uploader: null,
            error: null,
        };
    },
    methods: {

        // 选中文件上传
        selectFile (option) {

            return new Promise((resolve, reject) => {
                let filebox = document.querySelector('.filebox');
                let input = null;

                if (filebox) {
                    input = filebox.querySelector('input');
                } else {
                    filebox = document.createElement('div');
                    filebox.setAttribute('class', 'filebox');
                    filebox.setAttribute('style', ' position: absolute;left: 0;top: 0;width: 0;height: 0;overflow: hidden;opacity: 0;');
                    filebox.innerHTML = '<input type="file" accept="image/jpeg,image/jpg,image/png">';
                    document.body.appendChild(filebox);
                    input = filebox.querySelector('input');
                }

                const focusEvent = (event) => {
                    // 有可能有延时
                    window.removeEventListener('focus', focusEvent)
                    setTimeout(() => {
                        if (!input.lock) {
                            reject('Selected cancel', input.files.length)
                            // document.getElementById(input.id) && input.remove();
                        } else {
                            // input.remove();
                        }
                    }, 500)
                }

                input.onchange = () => {

                    if (input.files && input.files[0]) {
                        option.file = input.files[0];
                        let maxsize = 1024 * 1024 * 50; // 不能上传超过50M的图片
                        if (option.file.size > maxsize) {
                            // 图片过大
                            const notify = 'The maximum upload file size is 50M.'
                            this.$uxMessage.error(notify);
                            reject(notify)
                        } else {
                            resolve(option)
                        }
                    } else {
                        reject('No file select');
                    }
                    input.lock = true;
                    input.value = null;
                    filebox.remove();
                    // filebox.innerHTML = html;
                }

                // window.addEventListener('focus', focusEvent)
                input.click();
            })
        },

        getFileMime (option) {
            return new Promise((resolve, reject) => {

                let blob = option.file.slice(0, 128);//仅获取前128字节。
                let reader = new FileReader();
                reader.onloadend = function (e) {
                    let arr = (new Uint8Array(e.target.result)).subarray(0, 200);
                    let header = "";
                    const mime = [//type:类型，h：16字节标识【根据需要，自行添加】
                        { type: 'image/png', h: '89504e47' },
                        { type: 'image/gif', h: '47494638' },
                        { type: 'image/jpeg', h: 'ffd8ffe0,ffd8ffe1,ffd8ffe2,ffd8ffe3,ffd8ffe8' },
                        { type: 'image/webp', h: '524946461c' },
                        { type: 'Windows Bitmap/bmp', h: '424D' },
                        { type: 'TIFF/tif', h: '49492A00' },
                        { type: 'CAD/dwg', h: '41433130' },
                        { type: 'Adobe Photoshop/psd', h: '384250' },
                    ]
                    const check = (header) => {
                        for (let i in mime) {
                            let arr = mime[i].h.split(',');
                            let offset = (mime[i].offset || -1) + 1;//偏移量
                            for (let j in arr) {
                                let byte = arr[j].toLowerCase().replace(/\s+/g, "");
                                if (header.indexOf(byte) == offset) {
                                    return mime[i].type;
                                }
                            }
                        }
                        return 'unknown';
                    }


                    for (let i = 0; i < arr.length; i++) {
                        header += arr[i].toString(16);
                    }

                    option.mime = check(header);
                    option.suffix = option.mime.replace(/^[\w\W]*\/(\w+)/, '$1')

                    if (/(png|jpe?g)$/i.test(option.suffix)) {
                        resolve(option)
                    } else {
                        reject('Please check the image format')
                    }
                }
                reader.readAsArrayBuffer(blob);
            })

        },

        getFilePreview (option) {
            return new Promise((resolve, reject) => {
                const _URL = window.URL || window.webkitURL;
                const img = new Image();
                img.onload = () => {
                    option.image = img;
                    resolve(option);
                };
                img.onerror = (error) => { reject(String(error)) };
                img.src = _URL.createObjectURL(option.file);
            })
        },

        // 获取文件信息
        getFileInfo (option) {

            // 获取图片
            const getImage = new Promise((resolve, reject) => {
                const _URL = window.URL || window.webkitURL;
                const img = new Image();
                img.onload = () => {
                    option.image = img;
                    resolve();
                };
                img.onerror = (error) => { reject(String(error)) };
                img.src = _URL.createObjectURL(option.file);
            })

            // 获取文件信息
            const getMime = new Promise((resolve, reject) => {

                let blob = option.file.slice(0, 128);//仅获取前128字节。
                let reader = new FileReader();
                reader.onloadend = function (e) {
                    let arr = (new Uint8Array(e.target.result)).subarray(0, 200);
                    let header = "";
                    const mime = [//type:类型，h：16字节标识【根据需要，自行添加】
                        { type: 'image/png', h: '89504e47' },
                        { type: 'image/gif', h: '47494638' },
                        { type: 'image/jpeg', h: 'ffd8ffe0,ffd8ffe1,ffd8ffe2,ffd8ffe3,ffd8ffe8' },
                        { type: 'image/webp', h: '524946461c' },
                        { type: 'Windows Bitmap/bmp', h: '424D' },
                        { type: 'TIFF/tif', h: '49492A00' },
                        { type: 'CAD/dwg', h: '41433130' },
                        { type: 'Adobe Photoshop/psd', h: '384250' },
                    ]
                    const check = (header) => {
                        for (let i in mime) {
                            let arr = mime[i].h.split(',');
                            let offset = (mime[i].offset || -1) + 1;//偏移量
                            for (let j in arr) {
                                let byte = arr[j].toLowerCase().replace(/\s+/g, "");
                                if (header.indexOf(byte) == offset) {
                                    return mime[i].type;
                                }
                            }
                        }
                        return 'unknown';
                    }


                    for (let i = 0; i < arr.length; i++) {
                        header += arr[i].toString(16);
                    }

                    option.mime = check(header);
                    option.suffix = option.mime.replace(/^[\w\W]*\/(\w+)/, '$1')
                    resolve();
                }
                reader.readAsArrayBuffer(blob);
            })

            return Promise.all([getImage, getMime]).then(result => {
                if (/(png|jpe?g)$/i.test(option.suffix)) {
                    return Promise.resolve(option)
                } else {
                    return Promise.reject('Please check the image format')
                }
            })
        },
        uploadFile (option) {

            // 先上传大图
            // 再生成缩略图

            // 文件名
            if (!option.name) {
                const time = new Date().getTime();
                const random = Math.random().toFixed(10).substr(2);
                option.name = time + "-" + random + "." + option.suffix;
            }

            // 文件路径
            if (!option.path) {
                option.path = "data/zx/design/file/"
            }

            return new Promise((resolve, reject) => {

                // 递归循环上传，最多上次3次，太多次没有作用
                let count = 3;
                let doUpload = () => {
                    const request = {
                        file: option.file,
                        name: option.name,
                        path: option.path.replace(/\/+$/, '') + '/',
                        onprogress (event) {
                            option.percent = 5 + parseInt(0.9 * event.percent);
                            option.client = event.client;
                            option.cpt = event.cpt;
                        },
                    };

                    this.$uploadToOSS(request, response => {
                        if (response.code === 0 && response.data) {
                            option.url = response.data || '';
                            resolve(option);
                        } else if (--count < 0) {
                            reject(response.msg || "Upload more than 10 times");
                        } else if (this.uploader && this.uploader == option) {
                            setTimeout(() => doUpload(), 500);
                        } else {
                            // 新的上传
                        }
                    })
                };
                doUpload();
            });
        },

        // 生成缩略图
        createThumb (option) {
            return this.$http("Drawer.createThumb", { fullname: option.url }).then((result) => {
                if (!result || result.code !== 0) {
                    return Promise.reject("Failed to create thumbnail image");
                } else {
                    option.thumb = result.data;
                    return Promise.resolve(option);
                }
            }).catch(error => {
                return Promise.reject("Failed to create thumbnail image");
            })
        },

        // 开始上传
        startUpload (opt, callback) {
            const option = {
                path: opt.path || '', // 文件保存路径
                name: opt.name || '', // 文件保存的名称
                file: null, // 文件
                mime: '', // 媒体类型
                suffix: '', // 后缀名
                image: null, // 预览地址
                percent: 5, // 上传进度
                url: '', // 上传完成后最终路径
                thumb: '', // 生成的缩略图
                client: null, // oss引用
                cpt: null, // 分片上传引用
                status: 'select', // 当前状态 getinfo|upload|thumb|success|error
            }


            this.error = null;
            this.uploader = option;

            // 获取文件
            return this.selectFile(option).then(option => {
                // 获取图片信息
                return new Promise((resolve, reject) => {
                    this.$nextTick(e => {
                        option.status = 'getinfo';
                        this.getFileMime(option).then(resolve).catch(reject)
                    })
                });

            }).then(option => {
                if (this.uploader && this.uploader == option) {
                    return this.getFilePreview(option)
                } else {
                    return Promise.reject('Uploader is cancel')
                }
            }).then(option => {

                // 上传图片
                if (this.uploader && this.uploader == option) {
                    option.status = 'upload';
                    return this.uploadFile(option);
                } else {
                    return Promise.reject('Uploader is cancel')
                }

                // return new Promise((res, rej) => { })
            }).then(option => {
                // 生成缩略图
                if (this.uploader && this.uploader == option) {
                    option.status = 'thumb';
                    return this.createThumb(option);
                } else {
                    return Promise.reject('Uploader is cancel')
                }
            }).then(option => {
                // 上传成功
                if (this.uploader && this.uploader == option) {
                    option.status = 'success';
                    callback && callback(option);
                } else {
                    return Promise.reject('Uploader is cancel')
                }
            }).catch(error => {

                if (this.uploader && this.uploader == option) {
                    // 选择时如果不选中，则直接关闭
                    this.error = String(error);
                    option.status == 'select' && this.close();
                } else if (this.uploader) {
                    // 有新的上传
                } else {
                    this.close();
                }
            })
        },

        // 取消上传
        cancel () {
            if (this.uploader && this.uploader.client && this.uploader.cpt) {
                this.uploader.client.abortMultipartUpload(this.uploader.cpt.name, this.uploader.cpt.uploadId)
                this.uploader.client = null;
                this.uploader.cpt = null;
            }
            this.close();
        },
        close () {
            this.uploader = null;
            this.error = null;
        },

    }
};
</script>
<style lang="scss" scoped>
.filebox {
    position: absolute;
    left: 0;
    top: 0;
    width: 0;
    height: 0;
    overflow: hidden;
    opacity: 0;
}

.uploader {
    z-index: 1;
    width: 368px;
    box-sizing: border-box;
    padding: 24px;
    background: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: 8px;

    & > h2 {
        font-size: 16px;
        font-family: Roboto-Medium, Roboto;
        font-weight: 500;
        color: #000000;
        line-height: 18px;
    }

    h3 {
        margin-top: 14px;
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        text-align: center;
        font-size: 14px;
        font-family: Roboto-Regular, Roboto;
        font-weight: 400;
        color: #000000;
        line-height: 16px;
    }

    & > figure {
        width: 100%;
        margin-top: 12px;
        position: relative;
        background: #f1f1f1;
        &::before {
            content: '';
            display: block;
            padding-bottom: 100%;
        }
        img {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;

            &.uploader-error {
                width: 88px;
                height: 88px;
                left: 50%;
                top: 50%;
                transform: translate(-50%, -50%);
            }
        }
    }

    & > span {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        display: block;
        text-align: center;
        font-size: 12px;
        color: #000000;
        line-height: 14px;
        height: 14px;
        margin-top: 12px;
        font-weight: normal;
        color: #000000;
    }

    & > strong {
        margin-top: 4px;
        display: block;
        width: 100%;
        height: 10px;
        border-radius: 6px;
        display: block;
        position: relative;
        background-color: #ebebeb;
        margin-top: 4px;
        b {
            position: absolute;
            left: 0;
            top: 0;
            height: 100%;
            border-radius: 6px;
            background-color: #43b9e2;
        }
    }

    button {
        width: 160px;
        margin-top: 24px;
    }

    &[error='error'] {
        & > span em {
            color: #f44336;
        }
        & > strong b {
            background-color: #f44336;
        }
    }
}
</style>
